package com.cheetah.start.common.shoesImg;

import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class DeepStyleFeatures {

    /**
     * 提取对背景不敏感的深度特征（模拟）
     */
    public static Mat extractBackgroundAgnosticFeatures(Mat image) {
        List<Mat> featureMaps = new ArrayList<>();

        // 1. 多尺度颜色特征
        featureMaps.add(extractMultiScaleColorFeatures(image));

        // 2. 纹理特征
        featureMaps.add(extractMultiOrientationTexture(image));

        // 3. 形状上下文特征
        featureMaps.add(extractShapeContext(image));

        // 4. 边缘分布特征
        featureMaps.add(extractEdgeDistribution(image));

        // 合并所有特征
        Mat combinedFeatures = new Mat();
        for (Mat feature : featureMaps) {
            Core.hconcat(Arrays.asList(combinedFeatures, feature.reshape(1, 1)), combinedFeatures);
        }

        // 归一化
        Core.normalize(combinedFeatures, combinedFeatures, 1, 0, Core.NORM_L2);

        return combinedFeatures;
    }

    private static Mat extractMultiScaleColorFeatures(Mat image) {
        Mat hsv = new Mat();
        Imgproc.cvtColor(image, hsv, Imgproc.COLOR_BGR2HSV);

        // 在不同尺度下计算颜色直方图
        List<Mat> pyramids1 = buildGaussianPyramid(hsv, 3);

        Mat colorFeatures = new Mat();
        for (Mat level : pyramids1) {
            Mat hist = computeHSHistogram(level);
            Core.hconcat(Arrays.asList(colorFeatures, hist.reshape(1, 1)), colorFeatures);
        }

        return colorFeatures;
    }

    private static Mat extractMultiOrientationTexture(Mat image) {
        Mat gray = new Mat();
        Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);

        // 使用Gabor滤波器组提取多方向纹理
        Mat textureFeatures = new Mat();
        for (int i = 0; i < 4; i++) {
            double theta = i * Math.PI / 4;
            Mat gabor = createGaborKernel(8, theta, 4, 1, 0);
            Mat filtered = new Mat();
            Imgproc.filter2D(gray, filtered, -1, gabor);

            // 计算滤波结果的统计特征
            MatOfDouble mean = new MatOfDouble();
            MatOfDouble std = new MatOfDouble();
            Core.meanStdDev(filtered, mean, std);

            Mat features = new Mat(1, 2, CvType.CV_32F);
            features.put(0, 0, mean.get(0, 0)[0], std.get(0, 0)[0]);
            Core.hconcat(Arrays.asList(textureFeatures, features), textureFeatures);
        }

        return textureFeatures;
    }

    private static List<Mat> buildGaussianPyramid(Mat image, int levels) {
        List<Mat> pyramid = new ArrayList<>();
        pyramid.add(image);

        for (int i = 1; i < levels; i++) {
            Mat down = new Mat();
            Imgproc.pyrDown(pyramid.get(i - 1), down);
            pyramid.add(down);
        }

        return pyramid;
    }

    private static Mat computeHSHistogram(Mat hsv) {
        Mat hist = new Mat();
        Imgproc.calcHist(Arrays.asList(hsv), new MatOfInt(0, 1), new Mat(),
                hist, new MatOfInt(18, 12), new MatOfFloat(0, 180, 0, 256));
        Core.normalize(hist, hist, 1, 0, Core.NORM_L2);
        return hist.reshape(1, 1);
    }

    private static Mat createGaborKernel(int size, double theta, double lambda,
                                         double sigma, double gamma) {
        Mat kernel = new Mat(size, size, CvType.CV_32F);
        double halfSize = size / 2.0;

        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                double x = j - halfSize;
                double y = i - halfSize;

                double xPrime = x * Math.cos(theta) + y * Math.sin(theta);
                double yPrime = -x * Math.sin(theta) + y * Math.cos(theta);

                double gabor = Math.exp(-(xPrime * xPrime + gamma * gamma * yPrime * yPrime) / (2 * sigma * sigma))
                        * Math.cos(2 * Math.PI * xPrime / lambda);

                kernel.put(i, j, gabor);
            }
        }

        return kernel;
    }

    // 简化版的形状和边缘特征提取
    private static Mat extractShapeContext(Mat image) {
        Mat gray = new Mat();
        Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);
        Mat edges = new Mat();
        Imgproc.Canny(gray, edges, 50, 150);

        // 计算边缘的方向直方图
        Mat orientationHist = new Mat();
        Imgproc.calcHist(Arrays.asList(edges), new MatOfInt(0), new Mat(),
                orientationHist, new MatOfInt(8), new MatOfFloat(0, 256));
        Core.normalize(orientationHist, orientationHist, 1, 0, Core.NORM_L2);

        return orientationHist.reshape(1, 1);
    }

    private static Mat extractEdgeDistribution(Mat image) {
        Mat gray = new Mat();
        Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);
        Mat edges = new Mat();
        Imgproc.Canny(gray, edges, 50, 150);

        // 计算边缘的空间分布
        Mat distribution = new Mat(1, 4, CvType.CV_32F);

        // 分成4个区域计算边缘密度
        int halfWidth = gray.cols() / 2;
        int halfHeight = gray.rows() / 2;

        Rect[] regions = {
                new Rect(0, 0, halfWidth, halfHeight),
                new Rect(halfWidth, 0, halfWidth, halfHeight),
                new Rect(0, halfHeight, halfWidth, halfHeight),
                new Rect(halfWidth, halfHeight, halfWidth, halfHeight)
        };

        for (int i = 0; i < 4; i++) {
            Mat region = new Mat(edges, regions[i]);
            double density = Core.countNonZero(region) / (double) region.total();
            distribution.put(0, i, density);
        }

        return distribution;
    }
}
